/* power.cpp
Michael Zahniser, 12/12/09

Function definitions for the power operators: powers, roots, and logs.
*/

#include "Operators.h"

#include <cmath>

using std::string;

namespace {
	string Square = "square sq";
	static const Do<Square> square;
	
	string Cube = "cube";
	static const Do<Cube> cube;
	
	string SquareRoot = "squareroot sqrt";
	static const Do<SquareRoot> squareroot;
	
	string Power = "power pow **";
	static const Do<Power> power;
	
	string Root = "root";
	static const Do<Root> root;
	
	string Distance = "distance dist";
	static const Do<Distance> distance;
	
	string E = "e";
	static const Do<E> e_op;
	
	string Exp = "exp";
	static const Do<Exp> exp;
	
	string Log = "log10 log";
	static const Do<Log> log;
	
	string Ln = "loge ln";
	static const Do<Ln> ln;
	
	string Lg = "log2 lg";
	static const Do<Lg> lg;
	
	static const double e = 2.71828182845904523536;
}



template <> void Do<Square>::operator()(State &state) const
{
	double value = state.Pop();
	state.Push(value * value);
}



template <> void Do<Cube>::operator()(State &state) const
{
	double value = state.Pop();
	state.Push(value * value * value);
}



template <> void Do<SquareRoot>::operator()(State &state) const
{
	state.Push(std::sqrt(state.Pop()));
}



template <> void Do<Power>::operator()(State &state) const
{
	double b = state.Pop();
	state.Push(std::pow(state.Pop(), b));
}



template <> void Do<Root>::operator()(State &state) const
{
	double b = state.Pop();
	state.Push(std::pow(state.Pop(), 1. / b));
}



template <> void Do<Distance>::operator()(State &state) const
{
	double y = state.Pop();
	double x = state.Pop();
	y -= state.Pop();
	x -= state.Pop();
	state.Push(std::sqrt(x * x + y * y));
}



template <> void Do<E>::operator()(State &state) const
{
	state.Push(e);
}



template <> void Do<Exp>::operator()(State &state) const
{
	state.Push(std::exp(state.Pop()));
}



template <> void Do<Log>::operator()(State &state) const
{
	state.Push(std::log10(state.Pop()));
}



template <> void Do<Ln>::operator()(State &state) const
{
	state.Push(std::log(state.Pop()));
}



template <> void Do<Lg>::operator()(State &state) const
{
	state.Push(std::log(state.Pop()) / std::log(2.));
}
